; spinlock.asm
; Multipocessor safe spinlock implementation
;
;  Copyright 2006 Corey Tabaka
;
;  Licensed under the Apache License, Version 2.0 (the "License");
;  you may not use this file except in compliance with the License.
;  You may obtain a copy of the License at
;
;      http://www.apache.org/licenses/LICENSE-2.0
;
;  Unless required by applicable law or agreed to in writing, software
;  distributed under the License is distributed on an "AS IS" BASIS,
;  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;  See the License for the specific language governing permissions and
;  limitations under the License.
;

section .text
bits 32

; void spinlock_init(spinlock_t* ptr);
; int spinlock_wait(spinlock_t* ptr);
; void spinlock_signal(spinlock_t* ptr);
; int spinlock_try(spinlock_t* ptr);

[global _spinlock_init]
[global _spinlock_wait]
[global _spinlock_signal]
[global _spinlock_try]

_spinlock_init:
	mov edx,[esp + 4]
	mov dword [edx],0
	
	ret

_spinlock_wait:
	mov edx,[esp + 4]			; get the pointer to the mutex

.spin:
	cmp dword [edx],0			; check if lock is free (avoid too many bus locks)
	je .getlock
	pause
	jmp .spin
	
.getlock:	
	mov eax,1
	xchg eax,[edx]				; swap the mutex value with 1 (only one proc can do this at a time)
	cmp eax,0					; see if the mutex was locked
	jne .spin					; spin until we get a zero (previously unlocked) in eax
	
	mov eax,0
	ret

_spinlock_signal:
	mov edx,[esp + 4]			; get the pointer to the mutex
	mov dword [edx],0			; unlock mutex
	
	ret

_spinlock_try:
	mov edx,[esp + 4]			; pointer to mutex

	cmp dword [edx],0			; check if lock is free
	je .getlock
	
	mov eax,1					; return failure
	jmp .end
	
.getlock:	
	mov eax,1
	xchg eax,[edx]				; swap the mutex value with 1 (only one proc can do this at a time)
	
.end:
	ret
	
